package GameFrame

import (
	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/text"
	"image/color"
	"myGame/src/Config"
	"myGame/src/model"
	"myGame/src/tool"
	"strconv"
	"time"
)

//将游戏核心逻辑转移到game.go文件中，定义游戏对象结构和创建游戏对象的方法

// ebiten引擎传入的游戏对象必须要实现一个接口，让这个接口实现Game结构体的所有方法
// 这个接口说的是ebiten.RunGame(&GameFrame{})里面传参的这个Ganme类
// 让给Game结构体作为包含所有子结构体的，也算是项目的中间轴承一样的作用。
type Game struct {
	mode      Mode
	input     *Input
	realm     *model.Realm
	beijing   *model.Beijing
	live      *model.Live
	protect   *model.Protect
	obstacle  *model.Obstacle
	prop      *model.Prop
	Cfg       *Config.Config
	bullets   map[*model.Bullet]struct{}
	overMsg   string
	RealmDist float64
}

func NewGame() *Game {
	cfg := Config.LoadConfig()
	ebiten.SetWindowSize(cfg.ScreenWidth, cfg.ScreenHeight)
	ebiten.SetWindowTitle(cfg.Title)
	g := &Game{
		input:     &Input{Msg: "HelloWorld"},
		realm:     model.NewRealm(cfg.ScreenWidth, cfg.ScreenHeight),
		beijing:   model.NewBeijing(cfg.ScreenWidth, cfg.ScreenHeight),
		live:      model.NewLive(cfg.ScreenWidth, cfg.ScreenHeight),
		protect:   model.NewProtect(cfg.ScreenWidth, cfg.ScreenHeight),
		obstacle:  model.ObstacleInit(),
		prop:      model.NewProp(cfg.ScreenWidth, cfg.ScreenHeight),
		bullets:   make(map[*model.Bullet]struct{}),
		Cfg:       cfg,
		RealmDist: 0,
	}
	tool.NewMusic()
	tool.Play1music.Play()
	g.CreateFonts()
	return g
}

func (g *Game) Draw(screen *ebiten.Image) {
	screen.Fill(g.Cfg.BgColor)
	/**
	绘制一下游戏开始以及结束时候的文字显示
	启动时游戏处于ModeTitle状态，处于ModeTitle和ModeOver时只需要在屏幕上显示一些文字即可。
	只有在ModeGame状态才需要显示飞船和外星人：
	*/
	var titleTexts []string //它是一个切片  未定义数组长度
	var texts []string
	switch g.mode {
	case ModeTitle:
		titleTexts = []string{"ALIEN INVASION"}
		texts = []string{"", "", "", "", "", "", "", "PRESS SPACE KEY", "", "OR LEFT MOUSE"}
	case ModeGame:
		g.beijing.Draw(screen, g.Cfg, g.realm)
		g.obstacle.Draw(screen, g.Cfg)
		g.prop.Draw(screen, g.Cfg, g.realm)
		g.live.Draw(screen, g.Cfg, g.realm)
		g.protect.Draw(screen, g.Cfg, g.realm)
		g.realm.Draw(screen, g.Cfg)
		for bullet := range g.bullets {
			bullet.Draw(screen)
		}
		Str := "distant:" + strconv.FormatFloat(g.RealmDist, 'f', -1, 64)
		x := g.Cfg.ScreenWidth - len(Str)*g.Cfg.TitleFontSize
		//fmt.Println(x)
		text.Draw(screen, Str, titleArcadeFont, x, 100, color.White)
	case ModeOver:
		texts = []string{"", g.overMsg}
	}
	for i, l := range titleTexts {
		//。x 变量用于计算文本的水平位置，以便将文本居中对齐
		x := (g.Cfg.ScreenWidth - len(l)*g.Cfg.TitleFontSize) / 2
		//。text.Draw 函数用于在屏幕上绘制文本   i表示的是索引，l才是元素对象
		/**
		text.Draw 函数的第一个参数是要绘制的文本，第二个参数是字体对象，
		第三个参数是字体大小，第四个参数是文本的水平位置，第五个参数
		是文本的垂直位置，第六个参数是文本的颜色
		*/
		text.Draw(screen, l, titleArcadeFont, x, (i+4)*g.Cfg.TitleFontSize, color.White)
	}
	for i, l := range texts {
		x := (g.Cfg.ScreenWidth - len(l)*g.Cfg.FontSize) / 2
		text.Draw(screen, l, arcadeFont, x, (i+4)*g.Cfg.FontSize, color.White)
	}

}

func (g *Game) Update() error {
	switch g.mode {
	case ModeTitle:
		if g.input.IskeyPressed() {
			g.mode = ModeGame
		}
	case ModeGame:
		//人物行走的更新
		g.input.Update(g)
		//子弹弹道的更新
		for bullet := range g.bullets {
			if bullet.Dir == 0 {
				bullet.X -= bullet.SpeedFactor
			} else {
				bullet.X += bullet.SpeedFactor
			}
			//如果子弹溢出屏幕就把它删除掉
			if bullet.OutOfScreen(g.Cfg) {
				delete(g.bullets, bullet)
			}
			//判断子弹和道具的碰撞
			if tool.PropCollision(*g.prop, *bullet) && g.prop.State {
				g.prop.State = false
				delete(g.bullets, bullet)
				switch g.prop.Category {
				case 0:
					g.realm.Live++
				case 1:
					g.protect.LastTime = time.Now()
					g.protect.Display = true
				case 2:
					g.RealmDist += 5000
				}
			}
		}
		//这部分用来更新游戏的进行速度
		//人物奔跑距离的更新
		g.RealmDist += g.Cfg.RealmSpeedFactor
		switch {
		case g.RealmDist < 10000:
			g.Cfg.ObstacleSpeed = 5
		case g.RealmDist >= 10000 && g.RealmDist < 20000:
			g.Cfg.ObstacleSpeed = 8
		case g.RealmDist > 20000:
			g.Cfg.ObstacleSpeed = 10
		}

		//判断人物的保护罩的触发机制，即受伤就出现三秒，出现的时候便不在碰撞检测
		if tool.CheckCollision(g.obstacle, 0, g.realm) ||
			tool.CheckCollision(g.obstacle, 1, g.realm) {
			//如果保护套是false的时候，再把碰撞成功实现  并且把生命值等减少
			if !g.protect.Display {
				g.realm.Live--
				g.protect.LastTime = time.Now()
				g.protect.Display = true
			}
		}
		if time.Now().Sub(g.protect.LastTime).Milliseconds() >= 3000 {
			g.protect.Display = false
		}
		if g.realm.Live == 0 {
			g.overMsg = "Game Over!"
		}
		if len(g.overMsg) > 0 {
			time.Sleep(1 * time.Second)
			g.mode = ModeOver
			g.bullets = make(map[*model.Bullet]struct{})
			g.realm = model.NewRealm(g.Cfg.ScreenWidth, g.Cfg.ScreenHeight)
			g.beijing = model.NewBeijing(g.Cfg.ScreenWidth, g.Cfg.ScreenHeight)
			g.obstacle = model.ObstacleInit()
			g.Cfg.ObstacleSpeed = 5
			g.RealmDist = 0
		}
	case ModeOver:
		if g.input.IskeyPressed() {
			g.overMsg = ""
			g.mode = ModeTitle
		}
	}

	return nil
}

// 根据给定的outsideWidth和outsideHeight计算并返回适合的屏幕宽度和高度
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	return g.Cfg.ScreenWidth, g.Cfg.ScreenHeight
}

func (g *Game) addBullet(bullet *model.Bullet) {
	g.bullets[bullet] = struct{}{}
}
